﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Web;
using RazorEngine;
using Yahoo.Yui.Compressor;
using dotless.Core;

namespace Rejs
{
    public class Core : IHttpHandler
    {
        #region IHttpHandler Members

        /// <summary>
        /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests. </param>
        public void ProcessRequest(HttpContext context)
        {
            string relativePath = context.Request.AppRelativeCurrentExecutionFilePath;
            string absolutePath = context.Server.MapPath(relativePath);
            string result = File.ReadAllText(absolutePath);

            dynamic config = ConfigurationManager.GetSection("rejs");
            string[] excludedFiles = ((string[]) config.exclude.files.Split(',')).Select(p => p.Trim()).ToArray();

            if (!excludedFiles.Contains(context.Request.FilePath))
            {
                // Razor
                if (config.razor.enabled == "true")
                    result = DoRazor(result);

                // LESS
                if (config.less.enabled == "true")
                    result = DoLess(result);

                // YUI
                if (config.compression.enabled == "true")
                    result = DoYui(result);
            }
            // Send the result...
            context.Response.ContentType = "text/css";
            context.Response.Write(result);
        }

        /// <summary>
        /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
        /// </summary>
        /// <returns>
        /// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
        /// </returns>
        public bool IsReusable
        {
            get { return true; }
        }

        #endregion

        private string DoYui(string css)
        {
            return CssCompressor.Compress(css, 0, CssCompressionType.StockYuiCompressor, true);
        }

        private string DoLess(string css)
        {
            css = Less.Parse(css);

            return css;
        }

        private string DoRazor(string css)
        {
            IEnumerable<IRejsDataProvider> instances = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                                       from t in assembly.GetTypes()
                                                       where
                                                           t.GetInterfaces().Contains(typeof (IRejsDataProvider)) &&
                                                           t.GetConstructor(Type.EmptyTypes) != null
                                                       select Activator.CreateInstance(t) as IRejsDataProvider;

            dynamic external = new ExpandoObject();
            foreach (IRejsDataProvider instance in instances)
            {
                string name = instance.GetType().UnderlyingSystemType.Name;
                (external as IDictionary<String, Object>).Add(name, instance.Xyzzy());
            }

            dynamic data = new ExpandoObject();
            data.Request = HttpContext.Current.Request;
            data.CurrentFileName = HttpContext.Current.Request.FilePath;
            (data as IDictionary<String, Object>).Add("External", external);

            return Razor.Parse(css, data);
        }
    }
}